\section{Breve tutorial JDBC}

Nesta secção serão apresentados e explicados alguns exemplos de utilização do JDBC para aceder aos conteúdos de uma base de dados relacional.

\subsection{Instalação}
A instalação de um driver JDBC é tão simples como incluir um ficheiro jar no \gls{classpath}: 

$$\texttt{java -cp } \emph{driver.jar:... programa}$$

Em que \emph{driver.jar} é o ficheiro jar do driver que se pretende utilizar, e \emph{programa} é o nome da classe Java principal.

Depois no programa, antes do driver poder ser utilizado é necessário criar uma nova instância do driver utilizando:

$$\texttt{Class.forName(}\emph{nome}\texttt{);}$$

Em que \emph{nome} é uma String que possui o nome da classe que implementa a interface \texttt{java.sql.Driver}. Este nome pode ser obtido consultando a documentação que acompanha o driver.

Se o driver implementar a versão 4.0 da API JDBC, este último passo pode ser omitido, porque a versão 4.0 introduz o carregamento automático das classes que implementam \texttt{java.sql.Driver} e que estão presentes no \emph{classpath}, através do mecanismo Java SE Service Provider \cite{JDBCAPI}.

\subsection{Criar uma ligação} 
\label{sec:jdbctut-connection}
Para criar uma ligação ao servidor apenas utiliza-se o método:

$$\texttt{Driver.getConnection(}\emph{url}\texttt{);}. $$

O parâmetro \emph{url} é uma string no formato (note-se que o url está no formato para SQL Server 2008)\cite{MSJDBCURL}:
\begin{center}
\begin{verbatim}
   jdbc:sqlserver://[serverName[\instanceName][:portNumber]]
   [;property=value[;property=value]]
\end{verbatim}
\end{center}

Em que:
\begin{itemize}
  \item \texttt{jdbc:sqlserver://} é o sub-protocolo, é constante e obrigatório.
  \item \texttt{serverName} é o endereço do servidor.
  \item \texttt{instanceName} é uma instância no servidor.
  \item \texttt{portNumber} é o número da porta do serviço no servidor.
  \item \texttt{property} é uma propriedade da ligação. As propriedades para SQL Server 2008 podem ser consultadas em \cite{MSJDBCPROPERTIES}, e dois exemplos são o nome de utilizador e a password.
\end{itemize}

A Listagem \ref{lst:createcon} apresenta o código Java para a criação de uma ligação à base de dados utilizando JDBC.

\begin{lstlisting}[texcl=true,label={lst:createcon},caption={Criação de um objecto da ligação à base de dados.}]
// O valor de url deve ser alterado de acordo com a configuração do sistema.
String url = "jdbc:sqlserver://localhost:1433;database=AdventureWorks"
           + ";username=admin;password=admin";
Connection con = java.sql.DriverManager.getConnection(url);
\end{lstlisting}

\subsection{Executar uma query}

O resultado da execução de uma \gls{statement} denomina-se por result set ou \gls{dataset} e é obtido invocando o método \texttt{executeQuery} da interface \emph{Statement}. O resultado desse método é um objecto \emph{ResultSet} que fornece serviços para operar sobre as linhas do dataset, linha a linha. 
Para criar um result set, temos portanto, de estabelecer uma ligação com o servidor, criar uma statement\footnote{Instância de uma classe que implementa a interface \emph{Statement}.} e invocar o método executeQuery da statement, tal como demonstrado na Listagem \ref{lst:creaters}.

\begin{lstlisting}[texcl=true,label={lst:creaters},caption={Criação de um objecto result set.}]
String sql = "SELECT column1, column2 FROM mytable";
Statement stmt = con.createStatement(); // con é o objecto da ligação ao servidor
ResultSet rs = stmt.executeQuery(sql);
\end{lstlisting}

As operações disponíveis pelo objecto result set\footnote{Instância de uma classe que implementa a interface \emph{ResultSet}.} dependem do seu tipo.
A criação da statement (linha 2 da listagem anterior) determina o tipo de result set que é criado. Existem três versões do método createStatement\cite{JDBCCONNECTION}:
\begin{itemize}
  \item \texttt{createStatement() }
  \item \texttt{createStatement(int resultSetType, int resultSetConcurrency) }
  \item \texttt{createStatement(int resultSetType, \\int resultSetConcurrency, int resultSetHoldability) }
\end{itemize}

Os parâmetros válidos para estes métodos pertencem à interface \emph{ResultSet} e são descritos a seguir.

\texttt{resultSetType} pode ter um dos seguintes valores:
\begin{itemize}
  \item \texttt{TYPE\_FORWARD\_ONLY} O result set só pode ser percorrido numa direcção, da primeira para a última linha, e uma linha de cada vez.
  \item \texttt{TYPE\_SCROLLABLE\_SENSITIVE} O result set pode ser percorrido em qualquer direcção, e pode-se aceder a qualquer linha; as modificações externas são visíveis.
  \item \texttt{TYPE\_SCROLLABLE\_INSENSITIVE} O result set pode ser percorrido em qualquer direcção, e pode-se aceder a qualquer linha; as modificações externas não são visíveis.
\end{itemize}

\texttt{resultSetConcurrency} pode ter um dos seguintes valores:
\begin{itemize}
  \item \texttt{CONCUR\_READ\_ONLY} O result set só suporta operações de leitura.
  \item \texttt{CONCUR\_UPDATABLE} O result set também suporta operações de modificação.
\end{itemize}

\texttt{resultSetHoldability} pode ter um dos seguintes valores:
\begin{itemize}
  \item \texttt{HOLD\_CURSORS\_OVER\_COMMIT} Os cursores continuam abertos após a instrução de commit.
  \item \texttt{CLOSE\_CURSORS\_AT\_COMMIT} Os cursores são fechados após a instrução de commit.
\end{itemize}

O método createStatement sem argumentos cria por pré-definição um result set do tipo TYPE\_FORWARD\_ONLY/CONCUR\_UPDATABLE.

Por exemplo para criar um result set scrollable\footnote{Result set do tipo TYPE\_SCROLLABLE\_SENSITIVE ou TYPE\_SCROLLABLE\_INSENSITIVE, permitindo o acesso aleatório às suas linhas.} actualizável e sensível a actualizações externas criamos uma statement como demonstrado na Listagem \ref{lst:createsu}.

\begin{lstlisting}[texcl=true,label={lst:createsu},caption={Criação de um result set scrollable e actualizável.}]
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLLABLE_SENSIBLE,
                                     ResultSet.CONCUR_UPDATABLE);
\end{lstlisting}

\subsubsection{Ler os valores do result set}

O processamento do resultado é realizado linha a linha, e acede-se a uma linha movendo o cursor{\footnotemark} para essa linha. 
\footnotetext{O interface ResultSet fornece o mesmo tipo de funcionalidade que um cursor\cite{CursorsDatabaseEngine,CURSORSTSQL}, por isso diz-que que se está a mover o cursor quando se invoca uma operação que altera a linha em que o ResultSet se encontra.}


A Tabela \ref{tab:rsscroll} descreve os serviços da interface ResultSet que permitem mover o cursor.
\begin{table}[H]
  \caption{Serviços do ResultSet que permitem mover o cursor.}
  \label{tab:rsscroll}
  \centering
  \begin{tabular}{|l|l|}
  \hline
  \head{Método} & \head{Descrição}
  \\ \hline
  next & move para a próxima linha.
  \\ \hline
  previous & move para a linha anterior.
  \\ \hline
  absolute(n) & move para a linha n.
  \\ \hline
  relative(n) & move n linhas a partir da linha actual.
  \\ \hline
  first & move para a primeira linha.
  \\ \hline
  last & move para a última linha.
  \\ \hline
  beforeFirst & move para a posição anterior à primeira linha.
  \\ \hline
  afterLast & move para a posição posterior à última linha.
  \\ \hline
  \end{tabular}
\end{table}

Quando o result set é criado o cursor encontra-se antes da primeira linha. A Listagem \ref{readrs} exemplifica a leitura dos dados das colunas da primeira linha do result set.
\begin{lstlisting}[texcl=true,label={readrs},caption={Ler a primeira linha do result set.}]
rs.next(); // mover o cursor para a próxima linha
rs.getInt(1);  // ler o inteiro da primeira coluna
rs.getString(2); // ler a string da segunda coluna
\end{lstlisting}

Se o result set for do tipo TYPE\_FORWARD\_ONLY apenas o serviço \texttt{next} se encontra disponível, se um dos outros for invocado será apresentado um erro.

\subsubsection{Modificar os valores de um result set}
A interface ResultSet também permite actualizar os dados de um result set, mas a Statement que lhe dá origem tem que ser criada com o parâmetro resultSetConcurrency igual a CONCUR\_UPDATABLE.

A Tabela \ref{tab:rsupdate} descreve os serviços da interface ResultSet que permitem modificar os dados do dataset.
\begin{table}[H]
  \caption{Serviços do ResultSet que permitem modificar os dados do dataset.}
  \label{tab:rsupdate}
  \centering
  \begin{tabular}{|l|p{9cm}|}
  \hline
  \head{Método} & \head{Descrição}
  \\ \hline
  updateXXX(n, val) & Actualiza o valor da coluna n com o valor val. Existe um método update para cada tipo de dados, por isso XXX deve ser substituído por Int, String, Date, etc.
  \\ \hline
  updateRow & Envia para o servidor as modificações realizadas à linha.
  \\ \hline
  moveToInsertRow & Move o cursor para uma linha especial que depois pode ser enviada ao servidor para ser inserida no dataset.
  \\ \hline
  insertRow & Envia para o servidor uma linha que deve ser acrescentada ao dataset.
  \\ \hline
  moveToCurrentRow & Cancela a inserção da linha e move o cursor para a linha actual.
  \\ \hline
  deleteRow & Remove uma linha do dataset.  
  \\ \hline
  \end{tabular}
\end{table}

As listagens seguintes exemplificam uma operação de actualização, inserção e remoção, respectivamente.

\begin{lstlisting}[texcl=true,caption={Actualização de uma linha do result set.}]
// Criação do result set.
Statement stmt = con.createStatement(TYPE_SCROLL_SENSITIVE,
                                     CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery(sql);

// Actualização do result set.
rs.absolute(5);  // mover para a linha 5, será actualizada.
rs.updateInt(1, val1);  // actualizar a primeira coluna com o valor "val1"
rs.updateString(2, val2); // actualizar a segunda coluna com o valor "val2"
rs.updateRow(); // enviar as modificações para o servidor
\end{lstlisting}

\begin{lstlisting}[texcl=true,caption={Inserção de uma linha no result set.}]
// Criação igual ao exemplo anterior (...)

// Inserção de uma nova linha.
rs.moveToInsertRow(); // iniciar uma inserção.
rs.updateInt(1, val1); 
rs.updateString(2, val2);
rs.insertRow(); // enviar as modificações para o servidor.
rs.moveToCurrentrow(); // mover o cursor para linha actual.
\end{lstlisting}

\begin{lstlisting}[texcl=true,caption={Remoção de uma linha do result set.}]
// Criação igual ao exemplo anterior (...)

// Remoção de uma linha.
rs.last();  // mover para a última linha, que será removida.
rs.deleteRow(); // enviar as modificações para o servidor
\end{lstlisting}

